﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace AllenalaMente.Games.Recall
{
    public partial class Recall : UserControl, GameInterface
    {
        private DispatcherTimer updateTimer, startTimer;
        private TimeSpan startTime;
        private Random random;
        private Rectangle GrillRect;

        private int score;
        private int giuste, sbagliate, CheckGiuste = 0, CheckSbagliate = 0;

        private int difficulty = 1;
        private int numMaxItems = 3;

        private int Row = 3, Columns = 3, size = 80;

        // UI
        private UITimer UIgameTimer;
        private UIScore UIgameScore;

        public Recall()
        {
            InitializeComponent();

            // Initalize game
            random = new Random();
            score = 0;

            // Start timer
            startTimer = new DispatcherTimer();
            startTimer.Interval = TimeSpan.FromMilliseconds(600);
            startTimer.Tick += new EventHandler(startTimer_Tick);
            startTimer.Start();
            startTime = TimeSpan.FromSeconds(3);
            TextBlockReady.Text = Locale.Strings.Ready;

            // Update timer
            updateTimer = new DispatcherTimer();
            updateTimer.Interval = TimeSpan.FromMilliseconds(20);
            updateTimer.Tick += new EventHandler(updateTimer_Tick);
            //updateTimer.Start();

            // UI Game Timer
            UIgameTimer = new UITimer(60);
            LayoutRoot.Children.Add(UIgameTimer);
            UIgameTimer.timeOut += new EventHandler(game_TimeOut);
            //gameTimer.Start();

            // UI Game Score
            UIgameScore = new UIScore();
            LayoutRoot.Children.Add(UIgameScore);
            Canvas.SetLeft(UIgameScore, 750);

            //CreateCombination();
        }

        #region Metodi

        private List<int> numbers = new List<int>();

        private void CreateCombination()
        {
            canvasItem.Children.Clear();
            numbers.Clear();
            time = 0;

            switch (difficulty)
            {
                case 1:
                    Row = 3;
                    Columns = 3;
                    size = 100;
                    Canvas.SetLeft(canvasItem, 250);
                    break;

                case 2:
                    Row = 4;
                    Columns = 4;
                    size = 90;
                    Canvas.SetLeft(canvasItem, 200);
                    break;

                case 3:
                    Row = 5;
                    Columns = 5;
                    size = 70;
                    Canvas.SetLeft(canvasItem, 210);
                    break;
            }

            // Estrazione degli elementi da inserire
            for (int i = 0; i < Row * Columns; i++)
            {
                numbers.Add(0);
            }

            int itemsCount = 0;

            while (itemsCount < numMaxItems)
            {
                int index = random.Next(0, Row * Columns);

                if (numbers[index] == 0)
                {
                    numbers[index] = random.Next(1, 8);
                    itemsCount++;
                }
            }

            // Costruzione della griglia
            for (int r = 0; r < Row; r++)
            {
                for (int c = 0; c < Columns; c++)
                {
                    Rectangle rect = new Rectangle();
                    rect.Width = size;
                    rect.Height = size;
                    rect.StrokeThickness = 2;
                    rect.Stroke = new SolidColorBrush(Colors.Black);

                    canvasItem.Children.Add(rect);
                    Canvas.SetLeft(rect, r * size);
                    Canvas.SetTop(rect, c * size);
                    Canvas.SetZIndex(rect, 10);

                    rect.IsHitTestVisible = false;

                    Item item = new Item(numbers.First(), size);

                    numbers.Remove(numbers.First());

                    canvasItem.Children.Add(item);

                    Canvas.SetLeft(item, r * size);
                    Canvas.SetTop(item, c * size);
                    Canvas.SetZIndex(item, 10);

                    Show(item.image);
                }
            }

            GrillRect = new Rectangle();
            GrillRect.Width = size * Row;
            GrillRect.Height = size * Columns;
            GrillRect.Fill = new SolidColorBrush(Colors.Green);
            GrillRect.Opacity = 0.3;
            GrillRect.IsHitTestVisible = false;
            Canvas.SetLeft(GrillRect, 0);
            Canvas.SetTop(GrillRect, 0);
            Canvas.SetZIndex(GrillRect, 5);
            
            canvasItem.Children.Add(GrillRect);

            //canvasItem.MouseLeftButtonDown += new MouseButtonEventHandler(canvasItem_MouseLeftButtonDown);

            CheckGiuste = giuste;
            CheckSbagliate = sbagliate;
        }

        private void CheckSolution()
        {
            bool solved = true;

            for (int i = 0; i < canvasItem.Children.Count(); i++)
            {
                if (canvasItem.Children[i] is Item)
                {
                    if (!((Item)canvasItem.Children[i]).isVisible) { solved = false; }
                }
            }

            if (solved)
            {
                // Punti: 100 + (diff. lev * 10)
                IncreaseScore(100 + (difficulty * 10));
                FadeIn(GiustoImg);

                giuste++;

                numMaxItems++;

                if (giuste % 5 == 0) difficulty++;
                if (difficulty > 3) difficulty = 3;
            }
        }

        private void IncreaseScore(int amount)
        {
            score += amount;
            UIgameScore.SetScore(score);
        }

        #endregion

        #region Animations

        private void ShowSolution()
        {
            for (int i = 0; i < canvasItem.Children.Count(); i++)
            {
                if (canvasItem.Children[i] is Item)
                {
                    Item item = (Item)canvasItem.Children[i];
                    item.MouseLeftButtonDown -= new MouseButtonEventHandler(Item_MouseLeftButtonDown);

                    if (!item.isNone)
                    {
                        item.LayoutRoot.Background = new SolidColorBrush(Colors.Green);
                        //item.Opacity = 0.7;
                    }
                }
            }

            DoubleAnimation da = new DoubleAnimation() { From = 1, To = 1, Duration = new Duration(TimeSpan.FromSeconds(1.0)) };

            Storyboard.SetTargetProperty(da, new PropertyPath("Opacity"));
            Storyboard.SetTarget(da, this);

            Storyboard sb = new Storyboard();
            sb.Children.Add(da);
            sb.Completed += new EventHandler(Reset);
            sb.Begin();

            canvasItem.MouseLeftButtonDown += new MouseButtonEventHandler(Reset);
        }

        public void Show(UIElement element)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 0;
            doubleAnimation.To = 1;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.5));

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, element);

            Storyboard sb = new Storyboard();
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        public void hide(UIElement element)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 1;
            doubleAnimation.To = 0;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.1));



            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, element);

            Storyboard sb = new Storyboard();
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        public void FadeIn(UIElement element)
        {
            element.Opacity = 1;

            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 1;
            doubleAnimation.To = 0;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1.0));


            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, element);

            Storyboard sb = new Storyboard();
            sb.Completed += new EventHandler(Completed);
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        private void Completed(object sender, EventArgs e)
        {
            CreateCombination();
        }

        #endregion

        #region Eventi

        private void startTimer_Tick(object sender, EventArgs e)
        {
            startTime = startTime.Subtract(TimeSpan.FromSeconds(1));
            if (startTime.Seconds < 2)
                TextBlockReady.Text = Locale.Strings.GO;
            if (startTime.Seconds < 1)
            {
                // The countdown is finished, the game can start
                startTimer.Tick -= startTimer_Tick;
                CanvasCountdown.Visibility = Visibility.Collapsed;
                updateTimer.Start();
                UIgameTimer.Start();

                CreateCombination();
            }
        }

        void Reset(object sender, EventArgs e)
        {
            canvasItem.MouseLeftButtonDown -= new MouseButtonEventHandler(Reset);

            CreateCombination();
        }

        void canvasItem_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            time = 50;
            canvasItem.MouseLeftButtonDown -= new MouseButtonEventHandler(canvasItem_MouseLeftButtonDown);
        }

        void Item_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Item item = (Item)sender;

            if (item.isNone)
            {
                //ShowSolution();
                FadeIn(SbagliatoImg);
                sbagliate++;
            }
            else
            {
                item.MouseLeftButtonDown -= new MouseButtonEventHandler(Item_MouseLeftButtonDown);

                Show(item.image);
                item.isVisible = true;
                CheckSolution();
            }
        }

        public event GameEvent GameEnd;

        private int time = 0;
        private void updateTimer_Tick(object sender, EventArgs e)
        {
            if (time == 50)
            {
                canvasItem.MouseLeftButtonDown -= new MouseButtonEventHandler(canvasItem_MouseLeftButtonDown);

                for (int i = 0; i < canvasItem.Children.Count(); i++)
                {
                    if (canvasItem.Children[i] is Item)
                    {
                        Item item = (Item)canvasItem.Children[i];
                        item.MouseLeftButtonDown += new MouseButtonEventHandler(Item_MouseLeftButtonDown);
                        hide(item.image);
                    }
                }
            }

            time++;
        }

        private void game_TimeOut(object sender, EventArgs e)
        {
            // Finito il tempo
            GameEventArgs gea = new GameEventArgs();
            gea.reason = GameCloseReason.Timeout;
            gea.score = this.score;
            gea.giuste = giuste;
            gea.sbagliate = sbagliate;
            if (GameEnd != null)
                GameEnd(this, gea);
        }

        #endregion


    }
}
